#include <fstream>
#include <iostream>
#include <string>
#include <vector>

#include "instruction.h++"
#include "tpe.h++"

int main(int, char**);
void firstPass(const std::string&, std::vector<Instruction>&);
void secondPass(const std::string&, std::vector<Instruction>&);
void dump(const std::vector<Instruction>&);

int main(int argc, char** argv) {
	if (argc != 3) {
		std::cout << "Usage: " << argv[0] << " input output\n";
		return 1;
	}
	std::vector<Instruction> instructions;
	firstPass(argv[1], instructions);
	dump(instructions);
	secondPass(argv[2], instructions);
	return 0;
}

void firstPass(const std::string& filename, std::vector<Instruction>& instructions) {
	std::ifstream input(filename);
	if (input.is_open() == false) {
		std::cout << "ERROR: unable to open file: '" << filename << "'\n";
		exit(1);
	}
	size_t lineNo = 1;
	Tryte_t address = 0;
	std::string line;
	while (input.eof() == false) {
		getline(input, line);
		if (line.find('#') != std::string::npos) {
			line.erase(line.find('#'));
		}
		std::vector<std::string> tokens;
		while (line.find_first_not_of("\t ") != std::string::npos) {
			line.erase(0, line.find_first_not_of("\t "));
			tokens.push_back(std::string(line, 0, line.find_first_of("\t ")));
			line.erase(0, line.find_first_of("\t "));
		}
		while (tokens.size() != 0 && tokens.at(0).at(tokens.at(0).size() - 1) == ':') {
			Instruction::addSymbol(tokens.at(0).substr(0, tokens.at(0).size() - 1), address);
			tokens.erase(tokens.begin());
		}
		instructions.push_back(Instruction(filename, lineNo, address, tokens));
		++lineNo;
		address += instructions.back().getSize();
	}
	input.close();
}

void secondPass(const std::string& filename, std::vector<Instruction>& instructions) {
	std::ofstream output(filename);
	if (output.is_open() == false) {
		std::cout << "ERROR: unable to open file: '" << filename << "'\n";
		exit(1);
	}
	for (std::vector<Instruction>::iterator i = instructions.begin(); i != instructions.end(); ++i) {
		output << i->assemble();
	}
	output.close();
}

void dump(const std::vector<Instruction>& instructions) {
	std::cout << "Instructions:\n";
	for (std::vector<Instruction>::const_iterator i = instructions.begin(); i < instructions.end(); ++i) {
		std::cout << i->dump() << "\n";
	}
	std::cout << "Symbols:\n";
	std::cout << Instruction::dumpSymbols();
}

